package com.app.db.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

@Configuration
@MapperScan(basePackages = DataSourceConstant.M1_PACKAGE, sqlSessionFactoryRef = "m1SqlSessionFactory")
/**
 * 数据源配置
 * @author liuli
 */
public class M1DataSourceConfig {
    /**M1*/
    @Value("${m1.datasource.url}")
    private String m1Url;
    @Value("${m1.datasource.username}")
    private String m1User;
    @Value("${m1.datasource.password}")
    private String m1Password;
    /**S1*/
    @Value("${s1.datasource.url}")
    private String s1Url;
    @Value("${s1.datasource.username}")
    private String s1User;
    @Value("${s1.datasource.password}")
    private String s1Password;
    /**驱动*/
    @Value("${db.mysql.driverClassName}")
    private String driverClass;
    /**pool*/
    @Value("${m1pool.datasource.maxActive}")
    private Integer maxActive;
    @Value("${m1pool.datasource.minIdle}")
    private Integer minIdle;
    @Value("${m1pool.datasource.initialSize}")
    private Integer initialSize;
    @Value("${m1pool.datasource.maxWait}")
    private Long maxWait;
    @Value("${m1pool.datasource.timeBetweenEvictionRunsMillis}")
    private Long timeBetweenEvictionRunsMillis;
    @Value("${m1pool.datasource.minEvictableIdleTimeMillis}")
    private Long minEvictableIdleTimeMillis;
    @Value("${m1pool.datasource.testWhileIdle}")
    private Boolean testWhileIdle;
    @Value("${m1pool.datasource.testWhileIdle}")
    private Boolean testOnBorrow;
    @Value("${m1pool.datasource.testOnBorrow}")
    private Boolean testOnReturn;
    @Value("${m2pool.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private Integer maxPoolPreparedStatementPerConnectionSize;

    @Bean(name = "m1DataSource")
    @Primary
    public DataSource m1DataSource() {
        M1DynamicDataSource dynamicDataSource = M1DynamicDataSource.getInstance();
        DruidDataSource masterDataSource = new DruidDataSource();
        masterDataSource.setDriverClassName(driverClass);
        masterDataSource.setUrl(m1Url);
        masterDataSource.setUsername(m1User);
        masterDataSource.setPassword(m1Password);
        //连接池配置
        masterDataSource.setMaxActive(maxActive);
        masterDataSource.setMinIdle(minIdle);
        masterDataSource.setInitialSize(initialSize);
        masterDataSource.setMaxWait(maxWait);
        masterDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        masterDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        masterDataSource.setTestWhileIdle(testWhileIdle);
        masterDataSource.setTestOnBorrow(testOnBorrow);
        masterDataSource.setTestOnReturn(testOnReturn);
        masterDataSource.setValidationQuery("SELECT 'x'");
        masterDataSource.setPoolPreparedStatements(true);
        masterDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        //监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
        try {
            masterDataSource.setFilters("stat,wall");
        } catch (SQLException e) {
        }
        DruidDataSource slaveDataSource = new DruidDataSource();
        slaveDataSource.setDriverClassName(driverClass);
        slaveDataSource.setUrl(s1Url);
        slaveDataSource.setUsername(s1User);
        slaveDataSource.setPassword(s1Password);
        //连接池配置
        slaveDataSource.setMaxActive(maxActive);
        slaveDataSource.setMinIdle(minIdle);
        slaveDataSource.setInitialSize(initialSize);
        slaveDataSource.setMaxWait(maxWait);
        slaveDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        slaveDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        slaveDataSource.setTestWhileIdle(testWhileIdle);
        slaveDataSource.setTestOnBorrow(testOnBorrow);
        slaveDataSource.setTestOnReturn(testOnReturn);
        slaveDataSource.setValidationQuery("SELECT 'x'");
        slaveDataSource.setPoolPreparedStatements(true);
        slaveDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        try {
            //通过别名的方式配置扩展插件，常用的插件有：
            //监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
            slaveDataSource.setFilters("stat,wall");
        } catch (SQLException e) {
        }
        Map<Object,Object> map = new HashMap<>();
        map.put(DataSourceConstant.DB_MASTER1, masterDataSource);
        map.put(DataSourceConstant.DB_SLAVE1, slaveDataSource);
        dynamicDataSource.setTargetDataSources(map);
        // 默认数据源 MASTER
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
        return dynamicDataSource;
    }

    @Bean(name = "m1TransactionManager")
    @Primary
    public DataSourceTransactionManager m1TransactionManager() {
        return new DataSourceTransactionManager(m1DataSource());
    }

    @Bean(name = "m1SqlSessionFactory")
    @Primary
    public SqlSessionFactory m1SqlSessionFactory(@Qualifier("m1DataSource") DataSource m1DataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(m1DataSource);
        sessionFactory.setTypeAliasesPackage(DataSourceConstant.M1_PACKAGE);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(DataSourceConstant.M1_MAPPER_LOCATION));
        return sessionFactory.getObject();
    }

}